﻿import flash.display.BitmapData;
import flash.filters.BlurFilter;
import flash.geom.ColorTransform;
import flash.geom.Matrix;
import flash.geom.Point;
import flash.geom.Rectangle;
import kliment.utils._Type;
import mx.utils.Delegate;

import kliment.display.MCC;

/**
 * ...
 * @author	Kliment
 * @version	0.1.12
 */
class kliment.effect.BlurGlass {
	private var _BACK_COLOR:Number = 0x000000;
	private var _MASK_CT:ColorTransform;
	private var _START_POINT:Point;
	private var _BLUR_FILTER:BlurFilter;
	private var _target_mc:MovieClip;
	private var _glass_mc:MovieClip;
	private var _glass_bmp:BitmapData;
	private var _blur:Number;
	private var _quality:Number;
	private var _autoUpdate:Boolean;
	
	public function BlurGlass(target_mc:MovieClip, blur:Number, quality:Number, autoUpdate:Boolean) {
		_target_mc = target_mc;
		_blur = blur || 5;
		_quality = quality || 3;
		_autoUpdate = autoUpdate;
		
		_MASK_CT = new ColorTransform(0, 0, 0, 1, 0, 0, 0, 255);
		_START_POINT = new Point();
		_BLUR_FILTER = new BlurFilter(_blur, _blur, _quality);
		_init();
	}
	
	public function update():Void {
		_render();
	}
	
	private function _init():Void {
		_setDepths();
		
		_glass_mc = MCC.create(_target_mc._parent);
		_glass_mc.swapDepths(_target_mc.getDepth() - 1);
		autoUpdate = _autoUpdate;
		_render();
	}
	
	private function _setDepths():Void {
		var parent_mc:MovieClip = _target_mc._parent;
		var depth:Number = _target_mc.getDepth();
		var elements:Array = new Array();
		for (var i in parent_mc) {
			var item_mc = parent_mc[i];
			if (_Type.isDisplayObject(item_mc))
				elements.push(item_mc);
		}
		
		var lenght:Number = elements.length;
		var vector:Number = 0;
		for (var i:Number = 0; i < lenght; ++i ) {
			var item_mc = elements[i];
			item_mc.swapDepths(lenght - i + vector);
			if (item_mc == _target_mc)
				vector = -1;
		}
	}
	
	private function _render():Void {
		var parent_mc:MovieClip = _target_mc._parent;
		var bounds:Rectangle = MCC.getBounds(_target_mc).toRectangle();
		bounds.width = Math.round(bounds.width);
		bounds.height = Math.round(bounds.height);
		_glass_bmp.dispose();
		
		var p:Point = new Point(bounds.x, bounds.y);
		var globalP:Point = p.clone();
		parent_mc.localToGlobal(globalP);
		
		_setUpVisible(_glass_mc, false);
		
		var cMatrix:Matrix = _target_mc.transform.matrix;
		cMatrix.tx = -(p.x - _target_mc._x);
		cMatrix.ty = -(p.y - _target_mc._y);
		
		var mask_bmp:BitmapData = new BitmapData(bounds.width, bounds.height, true, _BACK_COLOR);
		mask_bmp.draw(_target_mc, cMatrix, _MASK_CT);
		
		var body_bmp:BitmapData = new BitmapData(bounds.width, bounds.height, true, _BACK_COLOR);
		body_bmp.draw(_root, new Matrix(1, 0, 0, 1, -globalP.x, -globalP.y));
		body_bmp.applyFilter(body_bmp, body_bmp.rectangle, _START_POINT, _BLUR_FILTER);
		_glass_bmp  = new BitmapData(bounds.width, bounds.height, true, _BACK_COLOR);
		//_glass_bmp.fillRect(body_bmp.rectangle, _BACK_COLOR);
		_glass_bmp.copyPixels(body_bmp, body_bmp.rectangle, _START_POINT, mask_bmp, _START_POINT, true);
		
		mask_bmp.dispose();
		body_bmp.dispose();
		
		_setUpVisible(_glass_mc, true);
		MCC.attachBitmap(_glass_mc, _glass_bmp);
		
		_glass_mc._x = p.x;
		_glass_mc._y = p.y;
	}
	
	private function _setUpVisible(target:MovieClip, value:Boolean):Void {
		var parent_mc:MovieClip = target._parent;
		if (!parent_mc)
			return;
		else 
			_setUpVisible(parent_mc, value);
			
		for (var i in parent_mc) {
			var item_mc = parent_mc[i];
			if (_Type.isDisplayObject(item_mc)) {
				if (item_mc == target) 
					break;
				item_mc._visible = value;
			}
		}
	}
	
	public function remove():Void {
		MCC.remove(_glass_mc);
		delete this;
	}
	
	public function get autoUpdate():Boolean { return _autoUpdate; }
	public function set autoUpdate(value:Boolean):Void 	{
		if (value)
			_glass_mc.onEnterFrame = Delegate.create(this, _render);
		else 
			delete _glass_mc.onEnterFrame;
		_autoUpdate = value;
	}
}